#ifndef CPU_INSTR_H
#define CPU_INSTR_H

#include "types.h"

static inline uint8_t inb(uint16_t port){
    uint8_t rv;
    //inb al,dx
    __asm__ __volatile__("inb %[p],%[v]":[v]"=a"(rv):[p]"d"(port));
    return rv;
}

static inline uint16_t inw(uint16_t port){
    uint16_t rv;
    //inb al,dx
    __asm__ __volatile__("in %[p],%[v]":[v]"=a"(rv):[p]"d"(port));
    return rv;
}

static inline void outb(uint16_t port,uint8_t data){
    //outb al,dx
    __asm__ __volatile__("outb %[d],%[p]"::[d]"a"(data),[p]"d"(port));
}

static inline void outw(uint16_t port,uint16_t data){
    //outb al,dx
    __asm__ __volatile__("out %[d],%[p]"::[d]"a"(data),[p]"d"(port));
}

//关中断
static inline void cli(){
    __asm__ __volatile__("cli");
}

//开中断
static inline void sti(){
    __asm__ __volatile__("sti");
}

static inline void lgdt(uint32_t start,uint32_t size){
    //该结果体用来设置到gdtr寄存器中
    struct
    {
        uint16_t limit;
        uint16_t start15_0;
        uint16_t start31_16;
    }gdt;

    gdt.start31_16 = start>>16;
    gdt.start15_0 = start&0xFFFF;
    gdt.limit = size-1;
    
    __asm__ __volatile__("lgdt %[g]"::[g]"m"(gdt));
}

static inline void lidt(uint32_t start,uint32_t size){
    //该结果体用来设置到idtr寄存器中
    struct
    {
        uint16_t limit;
        uint16_t start15_0;
        uint16_t start31_16;
    }idt;

    idt.start31_16 = start>>16;
    idt.start15_0 = start&0xFFFF;
    idt.limit = size-1;
    
    __asm__ __volatile__("lidt %[g]"::[g]"m"(idt));
}



static inline uint32_t read_cr0(){
    uint32_t cr0;
    __asm__ __volatile__("mov %%cr0,%[v]":[v]"=r"(cr0));
    return cr0;
}

static inline uint32_t write_cr0(uint32_t v){
    __asm__ __volatile__("mov %[vr],%%cr0"::[vr]"r"(v));
}

static inline uint32_t read_cr2(){
    uint32_t cr2;
    __asm__ __volatile__("mov %%cr2,%[v]":[v]"=r"(cr2));
    return cr2;
}

static inline uint32_t read_cr3(){
    uint32_t cr3;
    __asm__ __volatile__("mov %%cr3,%[v]":[v]"=r"(cr3));
    return cr3;
}

static inline uint32_t write_cr3(uint32_t v){
    __asm__ __volatile__("mov %[vr],%%cr3"::[vr]"r"(v));
}

static inline uint32_t read_cr4(){
    uint32_t cr4;
    __asm__ __volatile__("mov %%cr4,%[v]":[v]"=r"(cr4));
    return cr4;
}

static inline uint32_t write_cr4(uint32_t v){
    __asm__ __volatile__("mov %[vr],%%cr4"::[vr]"r"(v));
}

static inline void far_jump(uint32_t selector,uint32_t offset){
    uint32_t addr[] = {offset,selector};
    __asm__ __volatile__("ljmpl *(%[a])"::[a]"r"(addr));
}

static inline void hlt(){
    __asm__ __volatile__("hlt");
}

static inline void write_tr(uint16_t tss_seg){
    __asm__ __volatile__("ltr %%ax"::"a"(tss_seg));
}

static inline uint32_t read_eflags(){
    uint32_t eflags;

    __asm__ __volatile__("pushf\n\tpop %%eax":"=a"(eflags));
    return eflags;
}

static inline uint32_t write_eflags(uint32_t eflags){
    __asm__ __volatile__("push %%eax\n\tpopf"::"a"(eflags));
}

#endif
